package com.shm.leetcode;

import java.util.HashSet;
import java.util.List;

/**
 * 648. 单词替换
 * 在英语中，我们有一个叫做 词根(root)的概念，它可以跟着其他一些词组成另一个较长的单词——我们称这个词为 继承词(successor)。例如，词根an，跟随着单词 other(其他)，可以形成新的单词 another(另一个)。
 *
 * 现在，给定一个由许多词根组成的词典和一个句子。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根，则用最短的词根替换它。
 *
 * 你需要输出替换之后的句子。
 *
 *
 *
 * 示例 1：
 *
 * 输入：dictionary = ["cat","bat","rat"], sentence = "the cattle was rattled by the battery"
 * 输出："the cat was rat by the bat"
 * 示例 2：
 *
 * 输入：dictionary = ["a","b","c"], sentence = "aadsfasf absbs bbab cadsfafs"
 * 输出："a a b c"
 * 示例 3：
 *
 * 输入：dictionary = ["a", "aa", "aaa", "aaaa"], sentence = "a aa a aaaa aaa aaa aaa aaaaaa bbb baba ababa"
 * 输出："a a a a a a a a bbb baba a"
 * 示例 4：
 *
 * 输入：dictionary = ["catt","cat","bat","rat"], sentence = "the cattle was rattled by the battery"
 * 输出："the cat was rat by the bat"
 * 示例 5：
 *
 * 输入：dictionary = ["ac","ab"], sentence = "it is abnormal that this solution is accepted"
 * 输出："it is ab that this solution is ac"
 *
 *
 * 提示：
 *
 * 1 <= dictionary.length <= 1000
 * 1 <= dictionary[i].length <= 100
 * dictionary[i] 仅由小写字母组成。
 * 1 <= sentence.length <= 10^6
 * sentence 仅由小写字母和空格组成。
 * sentence 中单词的总量在范围 [1, 1000] 内。
 * sentence 中每个单词的长度在范围 [1, 1000] 内。
 * sentence 中单词之间由一个空格隔开。
 * sentence 没有前导或尾随空格。
 * @author SHM
 */
public class ReplaceWords {
    /**
     * 方法一：前缀哈希【通过】
     * 思路
     *
     * 遍历句子中每个单词，查看单词前缀是否为词根。
     *
     * 算法
     *
     * 将所有词根 roots 存储到集合 Set 中。遍历所有单词，判断其前缀是否为词根。如果是，则使用前缀代替该单词；否则不改变该单词。
     *
     * 复杂度分析
     *
     * 时间复杂度：O(\sum w_i^2)O(∑w
     * i
     * 2
     * ​
     *  )，其中 w_iw
     * i
     * ​
     *   是第 ii 个单词的长度。检查第 ii 个单词的所有前缀花费时间 O(w_i^2)O(w
     * i
     * 2
     * ​
     *  )。
     *
     * 空间复杂度：O(N)O(N)，其中 NN 是句子的长度，词根使用 rootset 存储。
     *
     * 作者：LeetCode
     * 链接：https://leetcode-cn.com/problems/replace-words/solution/dan-ci-ti-huan-by-leetcode/
     * @param dictionary
     * @param sentence
     * @return
     */
    public String replaceWords_2(List<String> dictionary, String sentence) {
        HashSet<String> hashSet = new HashSet<>();
        for (String s : dictionary) {
            hashSet.add(s);
        }

        StringBuilder ss = new StringBuilder();
        String[] s = sentence.split(" ");
        for (String s1 : s) {
            String prefix = "";
            for (int i = 1; i <= s1.length(); i++) {
                prefix = s1.substring(0,i);
                if (hashSet.contains(prefix)){
                    break;
                }
            }
            if (ss.length()>0){
                ss.append(" ");
            }
            ss.append(prefix);
        }
        return ss.toString();
    }


    public String replaceWords(List<String> dictionary, String sentence) {
        //建立前缀树
        TireNode tireNode = new TireNode();
        for (String s : dictionary) {
            tireNode.insert(s);
        }

        //产生替换后的新句子
        StringBuilder ss = new StringBuilder();
        String[] s = sentence.split(" ");
        for (String s1 : s) {
            if (ss.length()>0){
                ss.append(" ");
            }
            String s2 = tireNode.find(s1);
            ss.append(s2);
        }
        return ss.toString();
    }

    class TireNode{
        TireNode next[] = new TireNode[26];
        String sentence;
        TireNode(){};

        public void insert(String word){
            TireNode node = this;
            char[] chars = word.toCharArray();
            for (char aChar : chars) {
                if (node.next[aChar-'a']==null){
                    node.next[aChar-'a'] = new TireNode();
                }
                node = node.next[aChar-'a'];
            }
            node.sentence = word;
        }

        public String find(String prefix){
            TireNode node = this;
            char[] chars = prefix.toCharArray();
            for (char aChar : chars) {
                if (node==null){
                    break;
                }
                //如果当前节点已有词根，那么直接返回该词根
                //保证每个继承词都是被最短词根替换的
                if (node.sentence!=null){
                    return node.sentence;
                }
                node = node.next[aChar-'a'];
            }
            //没有在字典中找到该继承词所对应的词根，因此不产生替换
            return prefix;
        }
    }
}
